ci: make deps-locked check resilient to upstream releases#65
Merged
Conversation
…only on pyproject change) The "Verify lockfile is in sync" step previously ran uv pip compile with no output-file baseline, which floats every dependency to the latest satisfying release and then diffs against the committed lock. Any upstream publish of a new satisfying release (e.g. pytest 9.1.0 satisfying >=9.0.3 while the lock pins 9.0.3) produces a non-empty diff and fails the job with zero repo change — making the check permanently flaky on every open PR. Fix: seed the temp output file from the committed lock before running uv pip compile (cp requirements-dev.lock /tmp/requirements-dev.regenerated.lock, then -o /tmp/requirements-dev.regenerated.lock). Per uv 0.6.16 docs: "if the output file already exists, the existing versions will be preferred … unless --upgrade is specified." This preserves pytest==9.0.3 (and all other pins) when they already satisfy the pyproject constraint, so the diff is empty and the check passes. The real failure mode — pyproject adds/changes a dep without the lock being regenerated — still produces a non-empty diff and fails. Step 1 (pip install --require-hashes) and Step 3 (import check) are unchanged. The committed requirements-dev.lock is unchanged; no deps were bumped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
The "Verify lockfile is in sync with pyproject.toml" step in
.github/workflows/deps-locked.ymlranuv pip compilewith no baseline output file, which means uv resolves every dependency to the latest satisfying release on each run. The result is then diffed against the committedrequirements-dev.lock. Any upstream package release that satisfies a pyproject constraint causes a non-empty diff and a RED check with zero repo change.Concrete example:
requirements-dev.lockpinspytest==9.0.3(satisfiespytest>=9.0.3). pytest 9.1.0 was published upstream. The baseline-less recompile resolves to 9.1.0, the diff is non-empty, and the check fails on every PR and on main — despite no code change in this repo.What changed
A single
cpis prepended to the check step:Per uv 0.6.16 docs: "If the output file already exists, the existing versions will be preferred when resolving dependencies, unless
--upgradeis also specified." Seeding the temp file from the committed lock means a pin that already satisfies the pyproject constraint (e.g.pytest==9.0.3vs>=9.0.3) is preserved. The diff against the committed lock is empty and the check passes.Why it is still durable
The real failure mode — someone bumps a pyproject dependency without regenerating the lock — still causes the recompile to diverge from the committed lock (the new/changed dep produces a different resolution even with the existing-pin preference), so the diff is non-empty and the check fails as intended. This was verified locally with a throwaway pyproject modification adding
requests>=2.0.0to the dev extras.What was NOT touched
pip install --require-hashes -r requirements-dev.lock) is unchanged — this is the real supply-chain guarantee and remains the primary defense.requirements-dev.lockis unchanged.pytest==9.0.3remains the committed pin. No deps were bumped or regenerated.uses:entries remain SHA-pinned with version comments;test_workflow_pins.pypasses.Verification
Local reproduction against uv 0.6.16 on the committed lock (pytest 9.0.3 pinned, pytest 9.1.0 available upstream):
Full test suite: 511 passed, 1 skipped (
uv run --extra dev python -m pytest -qin project.venv).